# --coding:utf-8--

# Copyright 2021 xpstem.com
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from lelink.ev3operation import *
from lelink.eventbus import *
from lelink.ev3command import *
from lelink.ev3operation import *

class EV3Device:
    __slots__ = ("type_", "mode")

    def __init__(self, type_: int, mode: int):
        self.type_ = type_
        self.mode = mode


class EV3InputDevice(EV3Device):
    __slots__ = ("in_port")

    def __init__(self, in_port: InputPort, type_: int, mode: int):
        EV3Device.__init__(self, type_, mode)
        self.in_port = in_port

    def ready_raw(self, mode: int) -> int:
        pass

    def ready_pct(self, mode: int) -> int:
        pass

    def ready_si(self, mode: int) -> float:
        pass


class EV3OutputDevice(EV3Device):
    __slots__ = ("out_port")

    def __init__(self, out_port: OutputPort, type_: int, mode: int):
        EV3Device.__init__(self, type_, mode)
        self.out_port = out_port


class EV3Sensor(EV3InputDevice):
    __slots__ = ("_event_bus")

    def __init__(self, event_bus: EventBus, in_port: InputPort, type_: int, mode: int):
        EV3InputDevice.__init__(self, in_port, type_, mode)
        self._event_bus = event_bus

    def ready(self) -> bool:
        pass

    def ready_raw(self, mode: int) -> int:
        raw_value = ReturnParam(0, Data32(0))
        op = EV3InputOpFactory.OpInputDevice.ready_raw(
            self._event_bus.layer, self.in_port, Data8(0), Data8(mode), Data8(1), raw_value)
        cmd = EV3DirectCommand({op})
        self._event_bus.post_command(cmd)
        return raw_value.value.value

    def ready_pct(self, mode: int) -> int:
        pct_value = ReturnParam(0, Data32(0))
        op = EV3InputOpFactory.OpInputDevice.ready_pct(
            self._event_bus.layer, self.in_port, Data8(0), Data8(mode), Data8(1), pct_value)
        cmd = EV3DirectCommand({op})
        self._event_bus.post_command(cmd)
        return pct_value.value.value

    def ready_si(self, mode: int) -> float:
        si_value = ReturnParam(0, DataF(0))
        op = EV3InputOpFactory.OpInputDevice.ready_si(
            self._event_bus.layer, self.in_port, Data8(0), Data8(mode), Data8(1), si_value)
        cmd = EV3DirectCommand({op})
        self._event_bus.post_command(cmd)
        return si_value.value.value


class EV3ColorSensor(EV3Sensor):

    """ type code """
    TYPE = 29

    """ mode code """
    MODE_REFLECTED = 0
    MODE_AMBIENT = 1
    MODE_COLOR = 2
    MODE_REFLECTED_RAW = 3
    MODE_RGB_RAW = 4
    MODE_CALIBRATION = 5

    def __init__(self, event_bus: EventBus, in_port: InputPort, mode: int):
        EV3Sensor.__init__(self, event_bus, in_port, EV3ColorSensor.TYPE, mode)


class EV3IRSensor(EV3Sensor):

    """ type code """
    TYPE = 33

    """ mode code """
    MODE_PROXIMITY = 0
    MODE_SEEKER = 1
    MODE_REMOTE = 2
    MODE_REMOTE_ADVANCED = 3
    MODE_NOT_UTILIZED = 4
    MODE_CALIBRATION = 5

    def __init__(self, event_bus: EventBus, in_port: InputPort, mode: int):
        EV3Sensor.__init__(self, event_bus, in_port, EV3IRSensor.TYPE, mode)


class EV3TouchSensor(EV3Sensor):

    """ type code """
    TYPE = 16

    """ mode code """
    MODE_TOUCH = 0
    MODE_BUMP = 1

    def __init__(self, event_bus: EventBus, in_port: InputPort, mode: int):
        EV3Sensor.__init__(self, event_bus, in_port, EV3TouchSensor.TYPE, mode)


class EV3UltrasonicSensor(EV3Sensor):

    """ type code """
    TYPE = 30

    """ mode code """
    MODE_CM = 0
    MODE_INCH = 1
    MODE_LISTEN = 2
    MODE_SI_CM = 3
    MODE_SI_INCH = 4
    MODE_DC_CM = 5
    MODE_DC_INCH = 6

    def __init__(self, event_bus: EventBus, in_port: InputPort, mode: int):
        EV3Sensor.__init__(self, event_bus, in_port, EV3UltrasonicSensor.TYPE, mode)


class EV3GyroSensor(EV3Sensor):

    """ type code """
    TYPE = 32

    """ mode code """
    MODE_ANGLE = 0
    MODE_RATE = 1
    MODE_FAST = 2
    MODE_RATE_ANGLE = 3
    MODE_CALIBRATION = 4

    def __init__(self, event_bus: EventBus, in_port: InputPort, mode: int):
        EV3Sensor.__init__(self, event_bus, in_port, EV3GyroSensor.TYPE, mode)


class EV3ServoMotor(EV3OutputDevice):
    __slots__ = ("_event_bus", "sensor")

    """ mode code """
    MODE_DEGREE = 0
    MODE_ROTATION = 1
    MODE_POWER = 2

    def __init__(self, event_bus: EventBus, out_port: OutputPort, type_: int, mode: int):
        EV3OutputDevice.__init__(self, out_port, type_, mode)
        self._event_bus = event_bus
        self.sensor = EV3MotorSensor(event_bus, output_ports[out_port], type_, mode)

    def start(self) -> None:
        start_op = EV3OutputOpFactory.output_start(self._event_bus.layer, {self.out_port})
        cmd = EV3DirectCommand(start_op)
        self._event_bus.post_command(cmd)

    def stop(self, brake: Brake) -> None:
        stop_op = EV3OutputOpFactory.output_stop(self._event_bus.layer, {self.out_port}, brake)
        cmd = EV3DirectCommand(stop_op)
        self._event_bus.post_command(cmd)

    def start_on_power(self, power: int) -> None:
        power_op = EV3OutputOpFactory.output_power(self._event_bus.layer, {self.out_port}, power)
        start_op = EV3OutputOpFactory.output_start(self._event_bus.layer, {self.out_port})

        cmd = EV3DirectCommand({power_op, start_op})
        self._event_bus.post_command(cmd)

    def start_on_steppower(self, power: int, step1: int, step2: int, step3: int, brake: Brake) -> None:
        power_op = EV3OutputOpFactory.output_steppower(self._event_bus.layer, {self.out_port}, power, step1, step2, step3, brake)
        start_op = EV3OutputOpFactory.output_start(self._event_bus.layer, {self.out_port})

        cmd = EV3DirectCommand({power_op, start_op})
        self._event_bus.post_command(cmd)

    def start_on_timepower(self, power: int, time1: int, time2: int, time3: int, brake: Brake) -> None:
        power_op = EV3OutputOpFactory.output_timepower(self._event_bus.layer, {self.out_port}, power, time1, time2, time3, brake)
        start_op = EV3OutputOpFactory.output_start(self._event_bus.layer, {self.out_port})

        cmd = EV3DirectCommand({power_op, start_op})
        self._event_bus.post_command(cmd)

    def start_on_speed(self, speed: int) -> None:
        speed_op = EV3OutputOpFactory.output_speed(self._event_bus.layer, {self.out_port}, speed)
        start_op = EV3OutputOpFactory.output_start(self._event_bus.layer, {self.out_port})

        cmd = EV3DirectCommand({speed_op, start_op})
        self._event_bus.post_command(cmd)


class EV3LargeMotor(EV3ServoMotor):

    """ type code """
    TYPE = 7

    def __init__(self, event_bus: EventBus, out_port: OutputPort, mode: int):
        EV3ServoMotor.__init__(self, event_bus, out_port, EV3LargeMotor.TYPE, mode)


class EV3MediumMotor(EV3ServoMotor):
    """ type code """
    TYPE = 8

    def __init__(self, event_bus: EventBus, out_port: OutputPort, mode: int):
        EV3ServoMotor.__init__(self, event_bus, out_port, EV3MediumMotor.TYPE, mode)


class EV3MotorSensor(EV3Sensor):

    def __init__(self, event_bus: EventBus, in_port: InputPort, type_: int, mode: int):
        EV3Sensor.__init__(self, event_bus, in_port, type_, mode)